bl_info = {
    "name": "Morpher Tool for Blender - Perfect Layout",
    "author": "lane模型 & Assistant",
    "version": (1, 6, 0),
    "blender": (4, 5, 0),
    "location": "View3D > Sidebar > Morpher Tools",
    "description": "3ds Max风格Morpher工具，完美布局版本",
    "category": "Mesh",
    "support": "COMMUNITY"
}

import bpy
from bpy.types import Operator, Panel, UIList
from bpy.props import StringProperty, CollectionProperty, IntProperty

# ==================== 数据系统 ====================

class MorpherTargetItem(bpy.types.PropertyGroup):
    """Morpher目标数据项"""
    name: StringProperty(name="目标名称")
    target_object: StringProperty(name="目标物体")
    shapekey_name: StringProperty(name="形态键名称")

# ==================== 核心操作符 ====================

class MORPHER_OT_add_target(Operator):
    """添加Morpher目标"""
    bl_idname = "morpher.add_target"
    bl_label = "添加目标"
    bl_description = "将选中的目标物体添加为基础模型的形态键"
    bl_options = {'REGISTER', 'UNDO'}
    
    target_name: StringProperty(
        name="目标名称",
        description="为此目标命名",
        default="New Target"
    )
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH' and 
                len(context.selected_objects) >= 1)
    
    def invoke(self, context, event):
        base_obj = context.active_object
        target_objs = [obj for obj in context.selected_objects if obj != base_obj]
        if target_objs:
            self.target_name = target_objs[0].name
        else:
            self.target_name = "Target"
        
        return context.window_manager.invoke_props_dialog(self)
    
    def execute(self, context):
        base_obj = context.active_object
        target_objs = [obj for obj in context.selected_objects if obj != base_obj]
        
        if not target_objs:
            self.report({'ERROR'}, "请先选择目标物体，然后选择基础模型")
            return {'CANCELLED'}
        
        target_obj = target_objs[0]
        
        if len(base_obj.data.vertices) != len(target_obj.data.vertices):
            self.report({'ERROR'}, f"顶点数不匹配: 基础模型 {len(base_obj.data.vertices)} 顶点, 目标模型 {len(target_obj.data.vertices)} 顶点")
            return {'CANCELLED'}
        
        try:
            if not base_obj.data.shape_keys:
                base_obj.shape_key_add(name="Basis", from_mix=False)
            
            shapekey_name = f"Morph_{self.target_name}"
            shapekey = base_obj.shape_key_add(name=shapekey_name, from_mix=False)
            
            for i, vert in enumerate(shapekey.data):
                if i < len(target_obj.data.vertices):
                    world_co = target_obj.matrix_world @ target_obj.data.vertices[i].co
                    local_co = base_obj.matrix_world.inverted() @ world_co
                    vert.co = local_co
            
            if not hasattr(base_obj, 'morpher_targets'):
                base_obj.morpher_targets = CollectionProperty(type=MorpherTargetItem)
            
            new_target = base_obj.morpher_targets.add()
            new_target.name = self.target_name
            new_target.target_object = target_obj.name
            new_target.shapekey_name = shapekey_name
            
            shapekey.value = 0.0
            
            self.report({'INFO'}, f"已添加目标: {self.target_name}")
            return {'FINISHED'}
            
        except Exception as e:
            self.report({'ERROR'}, f"添加目标失败: {str(e)}")
            return {'CANCELLED'}
    
    def draw(self, context):
        layout = self.layout
        layout.prop(self, "target_name")

class MORPHER_OT_update_target(Operator):
    """更新Morpher目标"""
    bl_idname = "morpher.update_target"
    bl_label = "更新目标"
    bl_description = "更新选中的Morpher目标"
    bl_options = {'REGISTER', 'UNDO'}
    
    target_index: IntProperty(default=-1)
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH' and
                hasattr(context.active_object, 'morpher_targets') and
                len(context.active_object.morpher_targets) > 0)
    
    def execute(self, context):
        base_obj = context.active_object
        
        if self.target_index < 0 or self.target_index >= len(base_obj.morpher_targets):
            self.report({'ERROR'}, "无效的目标索引")
            return {'CANCELLED'}
        
        target_item = base_obj.morpher_targets[self.target_index]
        target_obj = bpy.data.objects.get(target_item.target_object)
        
        if not target_obj:
            self.report({'ERROR'}, f"目标物体不存在: {target_item.target_object}")
            return {'CANCELLED'}
        
        if len(base_obj.data.vertices) != len(target_obj.data.vertices):
            self.report({'ERROR'}, "顶点数不匹配，无法更新")
            return {'CANCELLED'}
        
        try:
            shapekey = base_obj.data.shape_keys.key_blocks.get(target_item.shapekey_name)
            if not shapekey:
                self.report({'ERROR'}, f"形态键不存在: {target_item.shapekey_name}")
                return {'CANCELLED'}
            
            current_value = shapekey.value
            
            for i, vert in enumerate(shapekey.data):
                if i < len(target_obj.data.vertices):
                    world_co = target_obj.matrix_world @ target_obj.data.vertices[i].co
                    local_co = base_obj.matrix_world.inverted() @ world_co
                    vert.co = local_co
            
            shapekey.value = current_value
            
            self.report({'INFO'}, f"已更新目标: {target_item.name}")
            return {'FINISHED'}
            
        except Exception as e:
            self.report({'ERROR'}, f"更新目标失败: {str(e)}")
            return {'CANCELLED'}

class MORPHER_OT_remove_target(Operator):
    """移除Morpher目标"""
    bl_idname = "morpher.remove_target"
    bl_label = "移除目标"
    bl_description = "移除选中的Morpher目标"
    bl_options = {'REGISTER', 'UNDO'}
    
    target_index: IntProperty(default=-1)
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH' and
                hasattr(context.active_object, 'morpher_targets') and
                len(context.active_object.morpher_targets) > 0)
    
    def execute(self, context):
        base_obj = context.active_object
        
        if self.target_index < 0 or self.target_index >= len(base_obj.morpher_targets):
            self.report({'ERROR'}, "无效的目标索引")
            return {'CANCELLED'}
        
        target_item = base_obj.morpher_targets[self.target_index]
        
        try:
            shapekey = base_obj.data.shape_keys.key_blocks.get(target_item.shapekey_name)
            if shapekey:
                base_obj.shape_key_remove(shapekey)
            
            base_obj.morpher_targets.remove(self.target_index)
            
            self.report({'INFO'}, f"已移除目标: {target_item.name}")
            return {'FINISHED'}
            
        except Exception as e:
            self.report({'ERROR'}, f"移除目标失败: {str(e)}")
            return {'CANCELLED'}

class MORPHER_OT_update_all_targets(Operator):
    """更新所有Morpher目标"""
    bl_idname = "morpher.update_all_targets"
    bl_label = "更新所有目标"
    bl_description = "更新所有Morpher目标"
    bl_options = {'REGISTER', 'UNDO'}
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH' and
                hasattr(context.active_object, 'morpher_targets') and
                len(context.active_object.morpher_targets) > 0)
    
    def execute(self, context):
        base_obj = context.active_object
        
        success_count = 0
        error_count = 0
        
        for i, target_item in enumerate(base_obj.morpher_targets):
            try:
                bpy.ops.morpher.update_target('EXEC_DEFAULT', target_index=i)
                success_count += 1
            except:
                error_count += 1
        
        if error_count > 0:
            self.report({'WARNING'}, f"更新完成: {success_count}成功, {error_count}失败")
        else:
            self.report({'INFO'}, f"已更新所有{success_count}个目标")
        
        return {'FINISHED'}

class MORPHER_OT_go_to_target(Operator):
    """跳转到目标物体"""
    bl_idname = "morpher.go_to_target"
    bl_label = "选择目标"
    bl_description = "选择并聚焦到目标物体"
    bl_options = {'REGISTER'}
    
    target_index: IntProperty(default=-1)
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH' and
                hasattr(context.active_object, 'morpher_targets') and
                len(context.active_object.morpher_targets) > 0)
    
    def execute(self, context):
        base_obj = context.active_object
        
        if self.target_index < 0 or self.target_index >= len(base_obj.morpher_targets):
            self.report({'ERROR'}, "无效的目标索引")
            return {'CANCELLED'}
        
        target_item = base_obj.morpher_targets[self.target_index]
        target_obj = bpy.data.objects.get(target_item.target_object)
        
        if not target_obj:
            self.report({'ERROR'}, f"目标物体不存在: {target_item.target_object}")
            return {'CANCELLED'}
        
        bpy.ops.object.select_all(action='DESELECT')
        target_obj.select_set(True)
        context.view_layer.objects.active = target_obj
        
        self.report({'INFO'}, f"已选择目标: {target_item.name}")
        return {'FINISHED'}

# ==================== 完美布局界面列表 ====================

class MORPHER_UL_targets_list(UIList):
    """Morpher目标列表 - 完美布局版本"""
    
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            # 单行布局：名称(20%) + 滑块(80%)
            row = layout.row(align=True)
            
            # 目标名称（左侧20%）
            name_col = row.column(align=True)
            name_col.scale_x = 0.2  # 名称占20%宽度
            name_row = name_col.row(align=True)
            name_row.label(text=item.name)
            
            # 滑块区域（右侧80%）
            slider_col = row.column(align=True)
            slider_col.scale_x = 0.8  # 滑块占80%宽度
            
            base_obj = context.active_object
            shapekey = base_obj.data.shape_keys.key_blocks.get(item.shapekey_name) if base_obj.data.shape_keys else None
            
            if shapekey:
                # 滑块
                slider_row = slider_col.row(align=True)
                slider_row.prop(shapekey, "value", text="", slider=True)
            else:
                error_row = slider_col.row(align=True)
                error_row.label(text="形态键丢失")
                
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text="", icon='SHAPEKEY_DATA')

# ==================== 完美布局面板界面 ====================

class MORPHER_PT_main_panel(Panel):
    """Morpher工具主面板 - 完美布局版本"""
    bl_label = "Morpher Tools v1.6"
    bl_idname = "MORPHER_PT_main_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Morpher Tools"
    
    def draw(self, context):
        layout = self.layout
        obj = context.active_object
        
        if not obj or obj.type != 'MESH':
            layout.label(text="请选择网格物体", icon='ERROR')
            return
        
        # 添加目标区域
        box = layout.box()
        box.label(text="添加目标", icon='ADD')
        
        selected_count = len(context.selected_objects)
        if selected_count >= 2:
            target_objs = [obj for obj in context.selected_objects if obj != context.active_object]
            if target_objs:
                box.label(text=f"准备添加: {target_objs[0].name} → {context.active_object.name}", icon='INFO')
                box.operator("morpher.add_target", text="添加为目标", icon='SHAPEKEY_DATA')
            else:
                box.label(text="请先选择目标物体", icon='INFO')
        else:
            box.label(text="选择说明:", icon='INFO')
            box.label(text="1. 选择目标物体")
            box.label(text="2. 选择基础模型(最后选择)")
            box.label(text="3. 点击'添加为目标'")
        
        # 完美布局的目标列表区域
        if hasattr(obj, 'morpher_targets') and obj.morpher_targets:
            box = layout.box()
            box.label(text="目标管理", icon='OUTLINER_OB_MESH')
            
            # 总控制按钮 - 横向放置在上方
            controls_row = box.row(align=True)
            
            # 操作按钮
            update_op = controls_row.operator("morpher.update_target", text="更新", icon='FILE_REFRESH')
            update_op.target_index = obj.morpher_targets_index
            
            goto_op = controls_row.operator("morpher.go_to_target", text="选择", icon='OBJECT_DATA')
            goto_op.target_index = obj.morpher_targets_index
            
            remove_op = controls_row.operator("morpher.remove_target", text="移除", icon='X')
            remove_op.target_index = obj.morpher_targets_index
            
            # 批量更新按钮
            controls_row.operator("morpher.update_all_targets", text="全部更新", icon='FILE_REFRESH')
            
            # 目标列表 - 使用完美布局
            list_row = box.row()
            list_row.template_list("MORPHER_UL_targets_list", "", obj, "morpher_targets", obj, "morpher_targets_index")
            
        else:
            box = layout.box()
            box.label(text="暂无目标", icon='INFO')
            box.label(text="添加目标后显示完美布局")
        
        # 使用说明
        box = layout.box()
        box.label(text="工作流指南", icon='QUESTION')
        
        box.label(text="1. 创建基础布线模型")
        box.label(text="2. 复制并编辑各个变体")
        box.label(text="3. 选择变体+基础模型添加")
        box.label(text="4. 使用滑块混合造型")

# ==================== 注册系统 ====================

classes = (
    MorpherTargetItem,
    MORPHER_OT_add_target,
    MORPHER_OT_update_target,
    MORPHER_OT_remove_target,
    MORPHER_OT_update_all_targets,
    MORPHER_OT_go_to_target,
    MORPHER_UL_targets_list,
    MORPHER_PT_main_panel,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    
    bpy.types.Object.morpher_targets = CollectionProperty(type=MorpherTargetItem)
    bpy.types.Object.morpher_targets_index = IntProperty(default=0)

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)
    
    try:
        del bpy.types.Object.morpher_targets
        del bpy.types.Object.morpher_targets_index
    except:
        pass

if __name__ == "__main__":
    register()